package uk.ac.imperial.gpaexpress.client;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.DisclosurePanel;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

public class AnalysisScreen extends Composite {

	private static final Binder binder = GWT.create(Binder.class);

	interface Binder extends UiBinder<Widget, AnalysisScreen> {}
	
	@UiField VerticalPanel analysisScreenPanel;
	@UiField HorizontalPanel analysisPanel;
	@UiField HorizontalPanel iteratePanel1;
	@UiField HorizontalPanel iteratePanel2;
	@UiField ListBox analysisList;
	@UiField ListBox experimentList;
	@UiField Label densityLabel;
	@UiField Button cancelButton;
	@UiField Button confirmButton;
	@UiField TextBox constant1;
	@UiField TextBox constant2;
	@UiField TextBox from1;
	@UiField TextBox from2;
	@UiField TextBox to1;
	@UiField TextBox to2;
	@UiField TextBox steps1;
	@UiField TextBox steps2;
	@UiField TextBox stepSize;
	@UiField TextBox stopTime;
	@UiField TextBox density;
	@UiField TextArea expressions;
	
	UserInterface ui;
	String analysisStr;
	
	public AnalysisScreen(UserInterface ui) {
		initWidget(binder.createAndBindUi(this));
		this.ui = ui;
	}

	@UiHandler("analysisList")
	void onAnalysisSelect(ChangeEvent event){
		int selectedIndex = analysisList.getSelectedIndex();
		if(selectedIndex==0){
			analysisPanel.setVisible(false);
		}else{
			analysisPanel.setVisible(true);
			if(selectedIndex==1)
				densityLabel.setText("density");
			
			if(selectedIndex==2)
				densityLabel.setText("replications");
		}
	}
	
	@UiHandler("experimentList")
	void onExperimentSelect(ChangeEvent event){
		int selectedIndex = experimentList.getSelectedIndex();
		if(selectedIndex==0){
			iteratePanel1.setVisible(false);
			iteratePanel2.setVisible(false);
		}else if(selectedIndex==1){
			iteratePanel1.setVisible(true);
			iteratePanel2.setVisible(false);
		}else if(selectedIndex==2){
			iteratePanel1.setVisible(true);
			iteratePanel2.setVisible(true);
		}
	}
	
	@UiHandler("cancelButton")
	void onCancelClick(ClickEvent event){
		DialogBox parent = (DialogBox) analysisScreenPanel.getParent().getParent().getParent();
		parent.hide();
	}
	
	@UiHandler("confirmButton")
	void onConfirmClick(ClickEvent event){
		if(validateFields()==true){
			extractFields();
			updateUI();
			ui.parseResponse = false;
			ui.modelTextForm.submit();
			DialogBox parent = (DialogBox) analysisScreenPanel.getParent().getParent().getParent();
			parent.hide();
		}
	}

	private boolean validateFields(){
		String errors = "";
		if(analysisList.getSelectedIndex()==0){
			errors += "Analysis type must be selected.\n";
		}else{
			if(density.getText().equals("")){
				errors += "Density cannot be null.\n";
			}else{
				if(density.getText().contains(".")){
					errors += "Density must be of type integer.\n";
				}
				if(density.getText().contains("-")){
					errors += "Density must be positive.\n";
				}
			}
			if(stepSize.getText().equals("")){
				errors += "StepSize cannot be null.\n";
			}else{
				if(!stepSize.getText().contains(".")){
					errors += "StepSize must be of type double.\n";
				}
				if(stepSize.getText().contains("-")){
					errors += "StepSize must be positive.\n";
				}
			}
			if(stopTime.getText().equals("")){
				errors += "StopTime cannot be null.\n";
			}else{
				if(!stopTime.getText().contains(".")){
					errors += "StopTime must be of type double.\n";
				}
				if(stopTime.getText().contains("-")){
					errors += "StopTime must be positive.\n";
				}
			}
		}
		if(experimentList.getSelectedIndex()>0){
			if(constant1.getText().equals("") || from1.getText().equals("") || to1.getText().equals("") || steps1.getText().equals("")){
				errors += "Iterate experiment parameters cannot be null.\n";
			}else{
				if(!from1.getText().contains(".") || !to1.getText().contains(".")){
					errors += "Iterate range values must be of type double.\n";
				}
				if(steps1.getText().contains(".")){
					errors += "Iterate steps must be of type integer.\n";
				}
			}
			if(experimentList.getSelectedIndex()>1){
				if(constant2.getText().equals("") || from2.getText().equals("") || to2.getText().equals("") || steps2.getText().equals("")){
					errors += "Iterate experiment cannot be null.\n";
				}else{
					if(!from2.getText().contains(".") || !to2.getText().contains(".")){
						errors += "Iterate range values must be of type double.\n";
					}
					if(steps2.getText().contains(".")){
						errors += "Iterate steps must be of type integer.\n";
					}
				}
			}
		}
			
		if(expressions.getText().equals("")){
			errors += "Expressions cannot be null.\n";
		}
		
		if(!errors.equals("")){
			Window.alert(errors);
			return false;
		}else{
			return true;
		}
	}
	
	private void extractFields(){
		analysisStr = "";
		int expSelect = experimentList.getSelectedIndex();
		int anlSelect = analysisList.getSelectedIndex();
		
		// Add iterate commands
		if(expSelect==0){
			
		}else if(expSelect>0){
			analysisStr += "Iterate " + constant1.getText() + " from " + from1.getText()
				+ " to " + to1.getText() + " in " + steps1.getText() + " steps\n";
			if(expSelect>1){
				analysisStr += "\t" + constant2.getText() + " from " + from2.getText()
					+ " to " + to2.getText() + " in " + steps2.getText() + " steps\n";
			}
		}
		   
		// Add analysis commands
		if(anlSelect==1){
			analysisStr += "ODEs(stopTime=" + stopTime.getText() + ",stepSize=" + stepSize.getText()
				+ ",density=" + density.getText() + ")";
		}else if(anlSelect==2){
			analysisStr += "Simulation(stopTime=" + stopTime.getText() + ",stepSize=" + stepSize.getText()
			+ ",replications=" + density.getText() + ")";
		}
		
		// Add plot commands
		if(expSelect==0){
			analysisStr += "{\n";
		}else{
			analysisStr += "{} plot{\n";
		}
		analysisStr += "\t" + expressions.getText() + "\n}";
	}
	
	void updateUI(){
		ui.analysisHeaders.setVisible(true);
		int row = ui.analysesGrid.getRowCount();
		ui.analysesGrid.resize(row + 1, 5);
		ui.analysesGrid.getCellFormatter().setHorizontalAlignment(row, 1, HasHorizontalAlignment.ALIGN_CENTER);
		ui.analysesGrid.getCellFormatter().setHorizontalAlignment(row, 2, HasHorizontalAlignment.ALIGN_CENTER);
		ui.analysesGrid.getCellFormatter().setVerticalAlignment(row, 0, HasVerticalAlignment.ALIGN_TOP);
		ui.analysesGrid.getCellFormatter().setVerticalAlignment(row, 1, HasVerticalAlignment.ALIGN_TOP);
		ui.analysesGrid.getCellFormatter().setVerticalAlignment(row, 2, HasVerticalAlignment.ALIGN_TOP);
		ui.analysesGrid.getCellFormatter().setVerticalAlignment(row, 3, HasVerticalAlignment.ALIGN_TOP);
		ui.analysesGrid.setHTML(row, 0, analysisList.getItemText(analysisList.getSelectedIndex()));
		ui.analysesGrid.setHTML(row, 1, stepSize.getText());
		ui.analysesGrid.setHTML(row, 2, stopTime.getText());
		if(experimentList.getSelectedIndex()==0)
			ui.analysesGrid.setHTML(row, 3, "none");
		else if(experimentList.getSelectedIndex()==1){
			Label range = new Label(constant1.getText() + "[" + from1.getText()
					+ " : " + steps1.getText() + " : " + to1.getText() + "]");
			ui.analysesGrid.setWidget(row, 3, range);
		}else if(experimentList.getSelectedIndex()==2){
			Label range1 = new Label(constant1.getText() + "[" + from1.getText()
					+ " : " + steps1.getText() + " : " + to1.getText() + "]");
			Label range2 = new Label(constant2.getText() + "[" + from2.getText()
					+ " : " + steps2.getText() + " : " + to2.getText() + "]");
			VerticalPanel rangePanel = new VerticalPanel();
			rangePanel.add(range1);
			rangePanel.add(range2);
			ui.analysesGrid.setWidget(row, 3, rangePanel);
		}
		DisclosurePanel expressionsDisclosure = new DisclosurePanel("show/hide");
		TextArea expressionsText = new TextArea();
		expressionsText.setCharacterWidth(25);
		expressionsText.setVisibleLines(5);
		expressionsDisclosure.setContent(expressionsText);
		expressionsText.setText(expressions.getText());
		ui.analysesGrid.setWidget(row, 4, expressionsDisclosure);
		
		ui.modelText.setText(ui.modelText.getText() + "\n\n" + analysisStr);
		ui.parseResponse = false;
		ui.modelTextForm.submit();
	}
}
